﻿using System;
using System.Collections.Generic;

namespace FluentParser.Utils
{
    public static class Tuple
    {
        #region Create

        public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
        {
            return new Tuple<T1, T2>(item1, item2);
        }

        public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3)
        {
            return new Tuple<T1, T2, T3>(item1, item2, item3);
        }

        public static Tuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4)
        {
            return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6);
        }

        #endregion Create

        #region Clone

        public static Tuple<T1, T2> Clone<T1, T2>(Tuple<T1, T2> item1)
        {
            return new Tuple<T1, T2>(item1.Item1, item1.Item2);
        }

        public static Tuple<T1, T2, T3> Clone<T1, T2, T3>(Tuple<T1, T2, T3> item1)
        {
            return new Tuple<T1, T2, T3>(item1.Item1, item1.Item2, item1.Item3);
        }

        public static Tuple<T1, T2, T3, T4> Clone<T1, T2, T3, T4>(Tuple<T1, T2, T3, T4> item1)
        {
            return new Tuple<T1, T2, T3, T4>(item1.Item1, item1.Item2, item1.Item3, item1.Item4);
        }

        public static Tuple<T1, T2, T3, T4, T5> Clone<T1, T2, T3, T4, T5>(Tuple<T1, T2, T3, T4, T5> item1)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item1.Item3, item1.Item4, item1.Item5);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Clone<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2, T3, T4, T5, T6> item1)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item1.Item3, item1.Item4, item1.Item5, item1.Item6);
        }

        #endregion Clone

        #region Combine 3

        public static Tuple<T1, T2, T3> Combine<T1, T2, T3>(T1 item1, Tuple<T2, T3> item2)
        {
            return new Tuple<T1, T2, T3>(item1, item2.Item1, item2.Item2);
        }

        public static Tuple<T1, T2, T3> Combine<T1, T2, T3>(Tuple<T1, T2> item1, T3 item2)
        {
            return new Tuple<T1, T2, T3>(item1.Item1, item1.Item2, item2);
        }

        #endregion Combine 3

        #region Combine 4

        public static Tuple<T1, T2, T3, T4> Combine<T1, T2, T3, T4>(Tuple<T1, T2> item1, Tuple<T3, T4> item2)
        {
            return new Tuple<T1, T2, T3, T4>(item1.Item1, item1.Item2, item2.Item1, item2.Item2);
        }

        public static Tuple<T1, T2, T3, T4> Combine<T1, T2, T3, T4>(T1 item1, T2 item2, Tuple<T3, T4> item3)
        {
            return new Tuple<T1, T2, T3, T4>(item1, item2, item3.Item1, item3.Item2);
        }

        public static Tuple<T1, T2, T3, T4> Combine<T1, T2, T3, T4>(T1 item1, Tuple<T2, T3> item2, T4 item3)
        {
            return new Tuple<T1, T2, T3, T4>(item1, item2.Item1, item2.Item2, item3);
        }

        public static Tuple<T1, T2, T3, T4> Combine<T1, T2, T3, T4>(Tuple<T1, T2> item1, T3 item2, T4 item3)
        {
            return new Tuple<T1, T2, T3, T4>(item1.Item1, item1.Item2, item2, item3);
        }

        public static Tuple<T1, T2, T3, T4> Combine<T1, T2, T3, T4>(T1 item1, Tuple<T2, T3, T4> item2)
        {
            return new Tuple<T1, T2, T3, T4>(item1, item2.Item1, item2.Item2, item2.Item3);
        }

        public static Tuple<T1, T2, T3, T4> Combine<T1, T2, T3, T4>(Tuple<T1, T2, T3> item1, T4 item2)
        {
            return new Tuple<T1, T2, T3, T4>(item1.Item1, item1.Item2, item1.Item3, item2);
        }

        #endregion Combine 4

        #region Combine 5

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, Tuple<T4, T5> item4)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4.Item1, item4.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(T1 item1, T2 item2, Tuple<T3, T4> item3, T5 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3.Item1, item3.Item2, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(T1 item1, Tuple<T2, T3> item2, T4 item3, T5 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2.Item1, item2.Item2, item3, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(Tuple<T1, T2> item1, T3 item2, T4 item3, T5 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item2, item3, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(T1 item1, Tuple<T2, T3> item2, Tuple<T4, T5> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2.Item1, item2.Item2, item3.Item1, item3.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(Tuple<T1, T2> item1, T3 item2, Tuple<T4, T5> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item2, item3.Item1, item3.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(Tuple<T1, T2> item1, Tuple<T3, T4> item2, T5 item3)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item2.Item1, item2.Item2, item3);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(T1 item1, T2 item2, Tuple<T3, T4, T5> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3.Item1, item3.Item2, item3.Item3);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(T1 item1, Tuple<T2, T3, T4> item2, T5 item3)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2.Item1, item2.Item2, item2.Item3, item3);
        }
        
        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(Tuple<T1, T2, T3> item1, T4 item2, T5 item3)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item1.Item3, item2, item3);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(Tuple<T1, T2> item1, Tuple<T3, T4, T5> item2)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item2.Item1, item2.Item2, item2.Item3);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(Tuple<T1, T2, T3> item1, Tuple<T4, T5> item2)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item1.Item3, item2.Item1, item2.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(T1 item1, Tuple<T2, T3, T4, T5> item2)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2.Item1, item2.Item2, item2.Item3, item2.Item4);
        }

        public static Tuple<T1, T2, T3, T4, T5> Combine<T1, T2, T3, T4, T5>(Tuple<T1, T2, T3, T4> item1, T5 item2)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1.Item1, item1.Item2, item1.Item3, item1.Item4, item2);
        }

        #endregion Combine 5

        #region Combine 6

        #region 2 4

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, Tuple<T3, T4, T5, T6> item2)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2.Item1, item2.Item2, item2.Item3, item2.Item4);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2, T3, T4> item1, Tuple<T5, T6> item2)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item1.Item3, item1.Item4, item2.Item1, item2.Item2);
        }

        #endregion 2 4

        #region 3 3

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2, T3> item1, Tuple<T4, T5, T6> item2)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item1.Item3, item2.Item1, item2.Item2, item2.Item3);
        }

        #endregion 3 3

        #region 1 1 4

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, Tuple<T3, T4, T5, T6> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3.Item1, item3.Item2, item3.Item3, item3.Item4);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, Tuple<T2, T3, T4, T5> item2, T6 item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2.Item1, item2.Item2, item2.Item3, item2.Item4, item3);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2, T3, T4> item1, T5 item2, T6 item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item1.Item3, item1.Item4, item2, item3);
        }

        #endregion 1 1 4

        #region 1 2 3

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, Tuple<T2, T3> item2, Tuple<T4, T5, T6> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2.Item1, item2.Item2, item3.Item1, item3.Item2, item3.Item3);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, Tuple<T2, T3, T4> item2, Tuple<T5, T6> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2.Item1, item2.Item2, item2.Item3, item3.Item1, item3.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, T3 item2, Tuple<T4, T5, T6> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2, item3.Item1, item3.Item2, item3.Item3);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, Tuple<T3, T4, T5> item2, T6 item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2.Item1, item2.Item2, item2.Item3, item3);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2, T3> item1, T4 item2, Tuple<T5, T6> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item1.Item3, item2, item3.Item1, item3.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2, T3> item1, Tuple<T4, T5> item2, T6 item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item1.Item3, item2.Item1, item2.Item2, item3);
        }
        #endregion 1 2 3

        #region 2 2 2

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, Tuple<T3, T4> item2, Tuple<T5, T6> item3)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2.Item1, item2.Item2, item3.Item1, item3.Item2);
        }

        #endregion 2 2 2

        #region 1 1 1 3

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, Tuple<T4, T5, T6> item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4.Item1, item4.Item2, item4.Item3);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, Tuple<T3, T4, T5> item3, T6 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3.Item1, item3.Item2, item3.Item3, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, Tuple<T2, T3, T4> item2, T5 item3, T6 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2.Item1, item2.Item2, item2.Item3, item3, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2, T3> item1, T4 item2, T5 item3, T6 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item1.Item3, item2, item3, item4);
        }

        #endregion 1 1 1 3

        #region 1 1 2 2

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, Tuple<T3, T4> item3, Tuple<T5, T6> item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3.Item1, item3.Item2, item4.Item1, item4.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, Tuple<T2, T3> item2, T4 item3, Tuple<T5, T6> item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2.Item1, item2.Item2, item3, item4.Item1, item4.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, Tuple<T2, T3> item2, Tuple<T4, T5> item3, T6 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2.Item1, item2.Item2, item3.Item1, item3.Item2, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, T3 item2, T4 item3, Tuple<T5, T6> item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2, item3, item4.Item1, item4.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, T3 item2, Tuple<T4, T5> item3, T6 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2, item3.Item1, item3.Item2, item4);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, Tuple<T3, T4> item2, T5 item3, T6 item4)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2.Item1, item2.Item2, item3, item4);
        }

        #endregion 1 1 2 2

        #region 1 1 1 1 2

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, Tuple<T5, T6> item5)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5.Item1, item5.Item2);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, Tuple<T4, T5> item4, T6 item5)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4.Item1, item4.Item2, item5);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, Tuple<T3, T4> item3, T5 item4, T6 item5)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3.Item1, item3.Item2, item4, item5);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(T1 item1, Tuple<T2, T3> item2, T4 item3, T5 item4, T6 item5)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2.Item1, item2.Item2, item3, item4, item5);
        }

        public static Tuple<T1, T2, T3, T4, T5, T6> Combine<T1, T2, T3, T4, T5, T6>(Tuple<T1, T2> item1, T3 item2, T4 item3, T5 item4, T6 item5)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1.Item1, item1.Item2, item2, item3, item4, item5);
        }
        #endregion 1 1 1 1 2

        #endregion Combine 6
    }

    public class Tuple<T1, T2>
    {
        public Tuple(T1 item1, T2 item2)
        {
            Item1 = item1;
            Item2 = item2;
        }

        public T1 Item1 { get; private set; }
        public T2 Item2 { get; private set; }

        public bool Equals(Tuple<T1, T2> other)
        {
            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
                   && EqualityComparer<T2>.Default.Equals(Item2, other.Item2);
        }

        public override bool Equals(object obj)
        {
            var other = obj as Tuple<T1, T2>;
            if (other != null)
                return Equals(other);
            return false;
        }

        public override int GetHashCode()
        {
            return EqualityComparer<T1>.Default.GetHashCode(Item1)
                   ^ EqualityComparer<T2>.Default.GetHashCode(Item2);
        }

        public override string ToString()
        {
            return String.Concat("(", Item1, ", ", Item2, ")");
        }
    }

    public class Tuple<T1, T2, T3>
    {
        public Tuple(T1 item1, T2 item2, T3 item3)
        {
            Item1 = item1;
            Item2 = item2;
            Item3 = item3;
        }

        public T1 Item1 { get; private set; }
        public T2 Item2 { get; private set; }
        public T3 Item3 { get; private set; }

        public bool Equals(Tuple<T1, T2, T3> other)
        {
            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
                   && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
                   && EqualityComparer<T3>.Default.Equals(Item3, other.Item3);
        }

        public override bool Equals(object obj)
        {
            var other = obj as Tuple<T1, T2, T3>;
            if (other != null)
                return Equals(other);
            return false;
        }

        public override int GetHashCode()
        {
            return EqualityComparer<T1>.Default.GetHashCode(Item1)
                   ^ EqualityComparer<T2>.Default.GetHashCode(Item2)
                   ^ EqualityComparer<T3>.Default.GetHashCode(Item3);
        }

        public override string ToString()
        {
            return String.Concat("(", Item1, ", ", Item2, ", ", Item3, ")");
        }
    }

    public class Tuple<T1, T2, T3, T4>
    {
        public Tuple(T1 item1, T2 item2, T3 item3, T4 item4)
        {
            Item1 = item1;
            Item2 = item2;
            Item3 = item3;
            Item4 = item4;
        }

        public T1 Item1 { get; private set; }
        public T2 Item2 { get; private set; }
        public T3 Item3 { get; private set; }
        public T4 Item4 { get; private set; }

        public bool Equals(Tuple<T1, T2, T3, T4> other)
        {
            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
                   && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
                   && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
                   && EqualityComparer<T4>.Default.Equals(Item4, other.Item4);
        }

        public override bool Equals(object obj)
        {
            var other = obj as Tuple<T1, T2, T3, T4>;
            if (other != null)
                return Equals(other);
            return false;
        }

        public override int GetHashCode()
        {
            return EqualityComparer<T1>.Default.GetHashCode(Item1)
                   ^ EqualityComparer<T2>.Default.GetHashCode(Item2)
                   ^ EqualityComparer<T3>.Default.GetHashCode(Item3)
                   ^ EqualityComparer<T4>.Default.GetHashCode(Item4);
        }

        public override string ToString()
        {
            return String.Concat("(", Item1, ", ", Item2, ", ", Item3, ", ", Item4, ")");
        }
    }

    public class Tuple<T1, T2, T3, T4, T5>
    {
        public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
        {
            Item1 = item1;
            Item2 = item2;
            Item3 = item3;
            Item4 = item4;
            Item5 = item5;
        }

        public T1 Item1 { get; private set; }
        public T2 Item2 { get; private set; }
        public T3 Item3 { get; private set; }
        public T4 Item4 { get; private set; }
        public T5 Item5 { get; private set; }

        public bool Equals(Tuple<T1, T2, T3, T4, T5> other)
        {
            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
                   && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
                   && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
                   && EqualityComparer<T4>.Default.Equals(Item4, other.Item4)
                   && EqualityComparer<T5>.Default.Equals(Item5, other.Item5);
        }

        public override bool Equals(object obj)
        {
            var other = obj as Tuple<T1, T2, T3, T4, T5>;
            if (other != null)
                return Equals(other);
            return false;
        }

        public override int GetHashCode()
        {
            return EqualityComparer<T1>.Default.GetHashCode(Item1)
                   ^ EqualityComparer<T2>.Default.GetHashCode(Item2)
                   ^ EqualityComparer<T3>.Default.GetHashCode(Item3)
                   ^ EqualityComparer<T4>.Default.GetHashCode(Item4)
                   ^ EqualityComparer<T5>.Default.GetHashCode(Item5);
        }

        public override string ToString()
        {
            return String.Concat("(", Item1, ", ", Item2, ", ", Item3, ", ", Item4, ", ", Item5, ")");
        }
    }

    public class Tuple<T1, T2, T3, T4, T5, T6>
    {
        public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
        {
            Item1 = item1;
            Item2 = item2;
            Item3 = item3;
            Item4 = item4;
            Item5 = item5;
            Item6 = item6;
        }

        public T1 Item1 { get; private set; }
        public T2 Item2 { get; private set; }
        public T3 Item3 { get; private set; }
        public T4 Item4 { get; private set; }
        public T5 Item5 { get; private set; }
        public T6 Item6 { get; private set; }

        public bool Equals(Tuple<T1, T2, T3, T4, T5, T6> other)
        {
            return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
                   && EqualityComparer<T2>.Default.Equals(Item2, other.Item2)
                   && EqualityComparer<T3>.Default.Equals(Item3, other.Item3)
                   && EqualityComparer<T4>.Default.Equals(Item4, other.Item4)
                   && EqualityComparer<T5>.Default.Equals(Item5, other.Item5)
                   && EqualityComparer<T6>.Default.Equals(Item6, other.Item6);
        }

        public override bool Equals(object obj)
        {
            var other = obj as Tuple<T1, T2, T3, T4, T5, T6>;
            if (other != null)
                return Equals(other);
            return false;
        }

        public override int GetHashCode()
        {
            return EqualityComparer<T1>.Default.GetHashCode(Item1)
                   ^ EqualityComparer<T2>.Default.GetHashCode(Item2)
                   ^ EqualityComparer<T3>.Default.GetHashCode(Item3)
                   ^ EqualityComparer<T4>.Default.GetHashCode(Item4)
                   ^ EqualityComparer<T5>.Default.GetHashCode(Item5)
                   ^ EqualityComparer<T6>.Default.GetHashCode(Item6);
        }

        public override string ToString()
        {
            return String.Concat("(", Item1, ", ", Item2, ", ", Item3, ", ", Item4, ", ", Item5, ", ", Item6, ")");
        }
    }
}